<template>
  <div class="wrapper" :ref="refs.wrapper">
    <van-search
      v-model="state.searchInput"
      :show-action="state.searchInput !== ''"
      placeholder="请输入股票代码或股票名称"
      @cancel="onCancel"
      @search="onSearch"
    ></van-search>
    <van-pull-refresh v-model="state.refreshing" @refresh="onRefresh">
      <van-list
        v-model:error="state.error"
        v-model:loading="state.loading"
        :finished="state.finished"
        error-text="出错了！点击重新加载"
        finished-text="没有更多了"
        @load="onLoad"
      >
        <van-row v-for="(item, index) in state.list" :id="`tr_${item.code}`" :key="index">
          <van-col>
            <van-cell :value="item.codeName"/>
            <van-cell :value="item.code"/>
          </van-col>
          <van-col>
            <van-cell :value="item.pctChg"/>
          </van-col>
        </van-row>
      </van-list>
    </van-pull-refresh>
    <van-sticky position="bottom">
      <van-row justify="space-between" style="background-color: white">
        <van-col>
          <van-cell>
            <template #value>
              <span>{{ state.currentPageNumber }}</span>
              <span>/{{ state.totalPage }}</span>
            </template>
          </van-cell>
        </van-col>
        <van-col>
          <van-cell is-link value="点击跳转" @click="state.showJumpInput = true"/>
        </van-col>
      </van-row>
    </van-sticky>
    <van-popup
      v-model:show="state.showJumpInput"
      position="bottom"
      round
      style="height: fit-content; padding-top: 30px"
    >
      <van-sticky :offset-bottom="15" position="bottom">
        <van-cell>
          <template #value>
            <van-row justify="space-around">
              <van-col>
                <van-field v-model="state.jumpInput" :placeholder="`可输入范围：${1}至${state.totalPage}`"></van-field>
              </van-col>
              <van-col>
                <van-button round type="primary" @click="onJump">确认跳转</van-button>
              </van-col>
            </van-row>
          </template>
        </van-cell>
      </van-sticky>
    </van-popup>
  </div>
</template>

<script>
import {reactive, computed, onMounted, ref} from "vue";
import axios from "axios";
import {isIterable, scrollToElem} from "@/js/utils";

export default {
  name: "stock-up-list",
  setup() {
    const state = reactive({
      searchInput: null,
      totalNumber: 0,
      pageSize: 10,
      totalPage: computed(() => Math.ceil(state.totalNumber / state.pageSize)),
      currentPageIndex: -1,
      currentPageNumber: computed(() => state.currentPageIndex + 1),
      refreshing: false,
      jumping: false,
      showJumpInput: false,
      jumpInput: null,
      cache: [],
      list: [],
      loading: false,
      error: false,
      finished: computed(() => state.totalPage === state.currentPageNumber),
    });

    const refs = reactive({
      wrapper: ref(null),
    })

    const queryTotalNumber = () => {
      return axios.post("/api/stock_basic/list", {
        pageNumber: 1,
        pageSize: 0,
      })
        .then(res => {
          const code = res.data.statusCode;
          console.log(res)
          if (code === 200) {
            return state.totalNumber = res.data.responseData.total;
          } else {
            return null;
          }
        });
    }

    const queryStocks = (index, size) => {
      return axios.post("/api/stock_basic/list", {
        pageNumber: index,
        pageSize: size,
      })
        .then(res => {
          const code = res.data.statusCode;
          if (code === 200) {
            const records = res.data.responseData.records;
            if (isIterable(records))
              for (let i = 0; i < records.length; i++)
                state.cache[index * size + i] = records[i];
            return records;
          } else {
            return null;
          }
        });
    }

    const addToList = (list) => {
      if (!isIterable(list))
        return false;
      for (const e of list)
        state.list.push(e);
      return true;
    }

    const loadPage = (index = null, useCache = false) => {
      // 默认加载第一页
      if (index === null)
        index = 0;

      if (useCache && state.cache[index * state.pageSize])
        return new Promise(resolve => {
          state.currentPageIndex = index;
          state.loading = false;
          resolve(state.error = !addToList(state.cache.slice(index * state.pageSize, index * state.pageSize + state.pageSize)));
        });
      else
        return queryStocks(index, state.pageSize)
          .then(records => {
            state.currentPageIndex = index;
            state.loading = false;
            return state.error = !addToList(records);
          });
    };

    const reload = () => {
      state.totalNumber = 0;
      state.cache = [];
      state.list = [];
      state.currentPageIndex = -1;
      state.refreshing = false;
      state.jumping = false;
      state.jumpInput = null;
      queryTotalNumber()
        .then(() => loadPage());
    };

    const doPageJump = (index) => {
      if (state.cache[index * state.pageSize]) {
        // 缓存命中
        const id = `tr_${state.cache[index * state.pageSize].code}`;
        const elem = document.getElementById(id);
        if (elem) {
          scrollToElem(elem);
          return;
        }
      }
      state.list = [];
      loadPage(index, true);
    }

    const doSearch = (keywords) => {
      console.log(keywords)
    }

    const onLoad = (index = null) => {
      state.loading = true;
      loadPage(index || state.currentPageIndex + 1, true);
    };

    const onRefresh = () => {
      state.loading = true;
      reload();
    };

    const onJump = () => {
      state.showJumpInput = false;
      state.jumping = true;
      state.loading = true;
      let jumpPage = state.jumpInput;
      state.jumpInput = null;
      if (jumpPage > state.totalPage) {
        state.jumping = false;
        state.loading = false;
      } else {
        if (jumpPage <= 0)
          jumpPage = 1;
        doPageJump(jumpPage - 1);
      }
    };

    const onSearch = () => {
      doSearch(state.searchInput);
    };

    const onCancel = () => {
      state.searchInput = null;
    };

    onMounted(() => {
      state.loading = true;
      reload();
    });

    return {
      state,
      refs,
      onLoad,
      onRefresh,
      onSearch,
      onCancel,
      onJump,
    };
  },
}
</script>

<style lang="scss" scoped>

.wrapper {
  padding: 20px;
}

</style>